﻿using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using swe.Core;

namespace swe.Test
{
	[TestClass]
	public class BranchTest
	{
		public class User
		{
			public string UserName;
			public bool Registered;
			public int Credit;
			public string SuperTitle;
		}


		private User _user;

		private StateMachine<User, User> CreateSm()
		{
			_user = new User();
			var rv = (StateMachine<User,User>)StateMachine<User, User>.Create("Initial")
				.State("Initial", (s, u) =>
									{
										if (String.IsNullOrEmpty(u.UserName) || u.UserName.Length <= 3)
										{
											u.Registered = false;
											u.Credit = 0;
											return StateMachine.Loop;
										}
										return StateMachine.NamedState("RegisteredUser");

									})
				.State("RegisteredUser", (s, u) =>
											{
												if (u.Registered == false)
													return StateMachine.NamedState("KickedUser");
												if (u.Credit > 0)
													return StateMachine.NamedState("PaidUser");
												if (u.Credit == 0)
													return StateMachine.Loop;
												if (u.Credit < 1000)
													return StateMachine.NamedState("SilverUser");
												return StateMachine.NamedState("GoldUser");
											}, StateType.Transfer)
				.State("SilverUser", (s, u) =>
											{
												u.SuperTitle = "SilverUser";
												return StateMachine.NamedState("RegisteredUser");
											})
				.State("GoldUser", (s, u) =>
											{
												u.SuperTitle = "GoldUser";
												return StateMachine.NamedState("RegisteredUser");
											})
				.State("KickedUser", (s, u) =>
										{
											u.UserName = "";
											u.Credit = 0;
											u.SuperTitle = "";
											u.Registered = false;
											return StateMachine.NamedState("Initial");
										})
				.BindTo(_user);
			return rv;
		}

		/// <summary>
		/// Note: This test does was designed for the previous API. Is not valid now. TODO: Fix it.
		/// </summary>
		[TestMethod]
		public void PayForUser()
		{
			var sm = CreateSm();

			sm.Process(); //Will be on the start
			Assert.AreEqual("Initial", sm.CurrentState); //Username should be set
			_user.UserName = "TestUser";
			sm.Process(); //RegisteredUser
			Assert.AreEqual("Registered", sm.Process()); //No way out of the current state
			_user.Registered = false; //Now user will be cicked
			sm.ProcessToStableState();

			_user.Registered = true;
			_user.Credit = 200; //Now add some credit and make the user silver
			sm.ProcessToStableState();
			Assert.AreEqual("SILVER!", _user.SuperTitle);
			sm.ProcessToStableState();
			_user.Credit = 2000; //Gold User
			sm.ProcessToStableState();
			Assert.AreEqual("GOLD!", _user.SuperTitle);
			sm.ProcessToStableState();
			_user.Credit = 0; //Now back to unpaid user
			sm.ProcessToStableState();
			Assert.AreEqual("", _user.SuperTitle);
			_user.Registered = false; //Kick out the user I don't like him
			sm.ProcessToStableState();
			Assert.AreEqual("", _user.UserName);
		}
	}
}
